package com.ruoyi.user.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.user.domain.RefundInfo;
import com.ruoyi.user.domain.UserOrder;
import com.ruoyi.user.service.IUserOrderService;
import com.ruoyi.user.service.impl.RefundInfoService;
import com.ruoyi.user.service.thirdpay.alipay.AlipayService;
import com.ruoyi.user.service.thirdpay.wx.WxPayService;
import com.ruoyi.user.utils.PayChannel;
import com.ruoyi.user.utils.RandomUtil;
import com.ruoyi.user.utils.ServerChargeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.logging.Logger;

/**
 * 统一退款控制器
 * 处理各种支付渠道的退款请求
 *
 * @author houyong
 */
@Controller
@RequestMapping(value = "/pay")
@RefreshScope
public class OrderRefundController {
    private static final Logger logger = Logger.getLogger(OrderRefundController.class.getName());

    /**
     * 支付宝退款订单90天
     */
    private static final Long ninetyTimeStamp = 90 * 24 * 60 * 60 * 1000L;

    private static final BigDecimal ONEHUNDRED = BigDecimal.valueOf(100);

    /**
     * 微信原生appid
     */
    @Value("${weixin.native.appid}")
    public String wxNativeAppId;

    /**
     * 微信原生支付 对应商户号 秘钥
     */
    @Value("${weixin.native.mchkey}")
    public String wxNativeMchKey;

    /**
     * 微信原生支付 对应商户号
     */
    @Value("${weixin.native.mchid}")
    public String wxNativeMchId;

    /**
     * 微信原生支付 成功 通知地址
     */
    @Value("${weixin.native.pay.success.notify.url}")
    public String wxNativePaySuccessNotifyUrl;

    /**
     * 微信原生支付 退款 通知地址
     */
    @Value("${weixin.native.refund.notify.url}")
    private String wxNativeRefundSuccessNotifyUrl;

    @Autowired
    private RefundInfoService refundInfoService;

    @Autowired
    private IUserOrderService userOrderService;

    @Autowired
    private AlipayService alipayService;

    @Autowired
    private WxPayService wxPayService;

    /**
     * 通过订单号查询系统订单
     *
     * @param orderId 订单ID
     * @return 用户订单
     */
    public UserOrder searchUserOrderBySysOrderId(String orderId) {
        return userOrderService.findOrderByOrderId(orderId);
    }

    /**
     * 判断订单是否可以退款
     *
     * @param userOrder    订单信息
     * @param refundAmount 退款金额
     * @return 是否可以退款
     */
    public boolean judgeRefundAmount(UserOrder userOrder, Integer refundAmount) {
        if (userOrder.getStatus().equals(PayChannel.TransactionStatus.PAYSUCCESS.getValue())) {
            return true;
        }
        if (userOrder.getStatus().equals(PayChannel.TransactionStatus.PARTIALREFUNDSUCCESS.getValue())) {
            BigDecimal sumRefund = refundInfoService.searchRefundSumPayByOrderId(userOrder.getOrderId(), userOrder.getChannel());
            BigDecimal totalFee = userOrder.getNeedPayTotalFee();
            return ServerChargeUtil.bigDecimal(totalFee.subtract(sumRefund)).compareTo(BigDecimal.valueOf(refundAmount).divide(ONEHUNDRED)) >= 0;
        }
        return false;
    }

    /**
     * 生成退款订单id
     *
     * @return 退款订单ID
     */
    private String getRefundOrderId() {
        return "RI" + System.currentTimeMillis() + RandomUtil.getRandomNumber();
    }

    /**
     * 新统一 退款接口
     *
     * @param orderId    订单ID
     * @param amount     退款金额(分)
     * @param refundDesc 退款描述
     * @return 退款结果
     */
    @RequestMapping(value = "/order/refund", method = {RequestMethod.GET, RequestMethod.POST})
    public AjaxResult refund(@RequestParam(value = "orderId", required = true) String orderId,
                             @RequestParam(value = "amount", required = true) Integer amount,
                             @RequestParam(value = "refundDesc", required = true) String refundDesc,
                             HttpServletRequest request, HttpServletResponse response) {
        try {
            UserOrder order = searchUserOrderBySysOrderId(orderId);
            logger.info("业务层传过来的退款金额为：" + amount);
            if (order.getStatus().equals(PayChannel.TransactionStatus.PAYSUCCESS.getValue()) ||
                    order.getStatus().equals(PayChannel.TransactionStatus.PARTIALREFUNDSUCCESS.getValue())) {
                return refund(orderId, amount, refundDesc);
            } else if (order.getStatus().equals(PayChannel.TransactionStatus.NOTPAY.getValue())) {
                return AjaxResult.error("订单没有支付不能进行退款操作 ");
            } else {
                return AjaxResult.error("订单已经完全退款");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("退款异常");
        }
    }

    /**
     * 支付宝 退款  退款结果使用同步的方式
     *
     * @param order      系统订单
     * @param refundInfo 退款记录
     * @return 退款结果
     */
    private AjaxResult alipayRefund(UserOrder order, RefundInfo refundInfo) {
        BigDecimal alipayRefundAmount = BigDecimal.valueOf(refundInfo.getAmount()).divide(ONEHUNDRED).setScale(2);
        try {
            if (System.currentTimeMillis() - order.getPayTime() <= ninetyTimeStamp) {
                AlipayTradeRefundResponse refundResponse = alipayService.alipayRefund(refundInfo.getRefundId(), order.getOrderId(), String.valueOf(alipayRefundAmount), refundInfo.getDescription());
                if (refundResponse.isSuccess()) {
                    refundInfoService.refundForAliPay(order, refundInfo, refundResponse);
                    return AjaxResult.success();
                } else {
                    return AjaxResult.error("支付宝 退款 错误");
                }
            } else {
                return AjaxResult.error("退款失败，原因：超过90天的订单不能进行退款操作");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return AjaxResult.error("支付宝退款失败");
        }
    }

    /**
     * 微信体系的退款  退款结果以异步通知结果为准
     * 微信原生支付
     * 微信公众号支付
     * 微信小程序支付
     *
     * @param order      系统订单
     * @param refundInfo 退款记录
     * @return 退款结果
     * @throws UnknownHostException 未知主机异常
     */
    private AjaxResult wxRefund(UserOrder order, RefundInfo refundInfo) {
        int wxRefundAmount = BigDecimal.valueOf(refundInfo.getAmount()).intValue();

        String appid = "";
        String mchid = "";
        String mchKey = "";
        String refundSuccessNotifyUrl = "";
        if (order.getChannel().equals(PayChannel.ChannelType.WX.getValue())) {
            appid = wxNativeAppId;
            mchid = wxNativeMchId;
            mchKey = wxNativeMchKey;
            refundSuccessNotifyUrl = wxNativeRefundSuccessNotifyUrl;
        }
        if (System.currentTimeMillis() - order.getPayTime() > 2 * ninetyTimeStamp) {
            return AjaxResult.error("微信超期订单不支持退款，原因：订单有效期已经超过90天 ");
        } else {
            Map<String, String> resultMap = wxPayService.wxRefund(appid, mchid, mchKey, wxRefundAmount, order.getNeedPayFee(), refundInfo.getRefundId(), refundInfo.getOrderId(), refundInfo.getDescription(), refundSuccessNotifyUrl);
            if ("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))) {
                refundInfo.setTradeNo(resultMap.get("out_refund_no"));
                refundInfoService.afterCallingwxRefundApiSaveRefundInfo(refundInfo);
                return AjaxResult.success();
            } else {
                return AjaxResult.error(resultMap.get("err_code_des"));
            }
        }
    }

    /**
     * 退款方法
     *
     * @param orderId      订单id
     * @param refundAmount 退款金额 分
     * @param refundDesc   退款备注
     * @return 退款结果
     * @throws UnknownHostException 未知主机异常
     */
    public AjaxResult refund(String orderId, Integer refundAmount, String refundDesc) {
        UserOrder order = searchUserOrderBySysOrderId(orderId);
        String refundId = getRefundOrderId();
        RefundInfo refundInfo = new RefundInfo(refundAmount, refundDesc, "admin", order.getOrderId(), BigDecimal.valueOf(refundAmount).divide(ONEHUNDRED, 2, RoundingMode.HALF_UP).setScale(2),
                order.getChannel(), null, RefundInfo.RefundStatus.PENDING.getValue(),
                false, System.currentTimeMillis(), null, null, null, refundId);
        if (judgeRefundAmount(order, refundAmount)) {
            refundInfo.setRefundType(order.getChannel());
            if (order.getChannel().equals(PayChannel.ChannelType.ALIPAY.getValue())) {
                return alipayRefund(order, refundInfo);
            } else if (order.getChannel().equals(PayChannel.ChannelType.WX.getValue())) {
                return wxRefund(order, refundInfo);
            } else {
                return AjaxResult.error("不支持的退款渠道");
            }
        } else {
            return AjaxResult.error("可退余额不足");
        }
    }
}